//
//  JD_AFNetworking.m
//  Jared_AFN_Cache
//
//  Created by Jared on 2017/1/18.
//  Copyright © 2017年 Jared. All rights reserved.
//

#import "JD_AFNetworking.h"
#import "JDMD5.h"
#import <objc/runtime.h>
#import "CommonResponseBody.h"


/**
 *  存放 网络请求的线程
 */
static NSMutableArray *sg_requestTasks;
static NSString *const MAIN_URL = @"";


@implementation JD_Cache

@end

static char *NSErrorStatusCodeKey = "NSErrorStatusCodeKey";

@implementation NSError (JDHttp)

- (void)setStatusCode:(NSInteger)statusCode{
    objc_setAssociatedObject(self, NSErrorStatusCodeKey, @(statusCode), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

- (NSInteger)statusCode{
    return [objc_getAssociatedObject(self, NSErrorStatusCodeKey) integerValue];
}

@end

@interface JD_AFNetworking ()
@property (nonatomic, strong) AFHTTPSessionManager *manager;
@property (nonatomic, assign, getter=isConnected) BOOL connected;/**<网络是否连接*/
@property (nonatomic, retain) NSURLSessionTask *task;
@end

@implementation JD_AFNetworking

- (AFHTTPSessionManager *)manager{
    static AFHTTPSessionManager *rManager = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        rManager = [AFHTTPSessionManager manager];
        rManager.responseSerializer = [AFJSONResponseSerializer serializer];
        rManager.responseSerializer.acceptableContentTypes = [NSSet setWithObjects:@"application/json", @"text/json", @"text/javascript",@"text/html",@"text/plain",@"image/jpg",@"application/x-javascript",@"keep-alive", nil];
        // 设置超时时间
        [rManager.requestSerializer willChangeValueForKey:@"timeoutInterval"];
        rManager.requestSerializer.timeoutInterval = 60.f;
        [rManager.requestSerializer didChangeValueForKey:@"timeoutInterval"];
    });
    return rManager;
}

- (BOOL)isConnected{
    struct sockaddr zeroAddress;
    bzero(&zeroAddress, sizeof(zeroAddress));
    zeroAddress.sa_len = sizeof(zeroAddress);
    zeroAddress.sa_family = AF_INET;
    
    SCNetworkReachabilityRef defaultRouteReachability =
    SCNetworkReachabilityCreateWithAddress(NULL, (struct sockaddr *)&zeroAddress);
    SCNetworkReachabilityFlags flags;
    
    BOOL didRetrieveFlags =
    SCNetworkReachabilityGetFlags(defaultRouteReachability, &flags);
    CFRelease(defaultRouteReachability);
    
    if (!didRetrieveFlags) {
        printf("Error. Count not recover network reachability flags\n");
        return NO;
    }
    
    BOOL isReachable = flags & kSCNetworkFlagsReachable;
    BOOL needsConnection = flags & kSCNetworkFlagsConnectionRequired;
    return (isReachable && !needsConnection) ? YES : NO;
}

- (JD_Cache *)getCache:(JDCacheType)cacheType url:(NSString *)url params:(NSDictionary *)params withRequest:(JDBlock)resultBlock{
    //缓存数据的文件名
    NSString *fileName = [self fileName:url params:params];
    NSData *data = [JD_CacheTool getCacheFileName:fileName];
    
    JD_Cache *cache = [[JD_Cache alloc] init];
    cache.fileName = fileName;
    if (data.length) {
        NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingAllowFragments error:nil];
        if (cacheType == JDCacheTypeReloadIgnoringLocalCacheData) {//忽略缓存，重新请求
            
        }else if (cacheType == JDCacheTypeReturnCacheDataDontLoad){//有缓存就用缓存，没有缓存就不发请求，当做请求出错处理（用于离线模式）
            if (resultBlock) {
                resultBlock(dict, nil);
            }
        }else if (cacheType == JDCacheTypeReturnCacheDataElseLoad){//有缓存就用缓存，没有缓存就重新请求(用于数据不变时)
            if (resultBlock) {
                resultBlock(dict, nil);
            }
            cache.result = YES;
        }else if (cacheType == JDCacheTypeReturnCacheDataThenLoad){///有缓存就先返回缓存，同步请求数据
            if (resultBlock) {
                resultBlock(dict, nil);
            }
        }else if (cacheType == JDCacheTypeReturnCacheDataExpireThenLoad){
            //有缓存 判断是否过期了没有 没有就返回缓存
            //判断是否过期
            if (![JD_CacheTool isExpire:fileName]) {
                if (resultBlock) {
                    resultBlock(dict, nil);
                }
                cache.result = YES;
            }
        }
        
    }
    return cache;
}

- (NSString *)fileName:(NSString *)url params:(NSDictionary *)params{
    NSMutableString *mStr = [NSMutableString stringWithString:url];
    if (params != nil) {
        NSData *data = [NSJSONSerialization dataWithJSONObject:params options:NSJSONWritingPrettyPrinted error:nil];
        NSString *str = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
        [mStr appendString:str];
    }
    return mStr;
}


/////------网络请求-----/////
-(void)requestWithURL:(NSString *)url withParams:(NSDictionary *)params withCacheType:(JDCacheType)cacheType withRequestType:(NetworkRequestType)requestType withResult:(JDBlock)resultBlock{
    if (!self.isConnected) {
        NSLog(@"没有网络");
        //        return;
    }
    switch (requestType) {
        case NetworkGetType:
        {
            JD_Cache *cache = [self getCache:cacheType url:url params:params withRequest:resultBlock];
            NSString *fileName = cache.fileName;
            if (cache.result) {
                return;
            }
            /*
             [self.manager GET:url parameters:params progress:^(NSProgress * _Nonnull downloadProgress) {
             
             } success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
             NSLog(@"responseObject===%@", responseObject);
             if (resultBlock) {
             //缓存数据
             NSData *data = [NSJSONSerialization dataWithJSONObject:responseObject options:NSJSONWritingPrettyPrinted error:nil];
             [JD_CacheTool cacheForData:data fileName:fileName];
             [self handleRequestReslutWithDataTask:task responseObject:responseObject error:nil resultBlock:resultBlock];
             }
             } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
             NSLog(@"%@", error);
             [self handleRequestReslutWithDataTask:task responseObject:nil error:error resultBlock:resultBlock];
             }];
             */
            [self.manager GET:url parameters:params success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
                if (resultBlock) {
                    NSData *data = [NSJSONSerialization dataWithJSONObject:responseObject options:NSJSONWritingPrettyPrinted error:nil];
                    [JD_CacheTool cacheForData:data fileName:fileName];
                    [self handleRequestReslutWithDataTask:task responseObject:responseObject error:nil resultBlock:resultBlock];
                }
            } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
                [self handleRequestReslutWithDataTask:task responseObject:nil error:error resultBlock:resultBlock];
            }];
        }
            break;
        case NetworkPostType:
        {
            JD_Cache *cache = [self getCache:cacheType url:url params:params withRequest:resultBlock];
            NSString *fileName = cache.fileName;
            if (cache.result) {
                return;
            }
            /*
             [self.manager POST:url parameters:params progress:^(NSProgress * _Nonnull uploadProgress) {
             
             } success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
             //缓存数据
             if (resultBlock) {
             NSData *data = [NSJSONSerialization dataWithJSONObject:responseObject options:NSJSONWritingPrettyPrinted error:nil];
             [JD_CacheTool cacheForData:data fileName:fileName];
             [self handleRequestReslutWithDataTask:task responseObject:responseObject error:nil resultBlock:resultBlock];
             }
             } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
             [self handleRequestReslutWithDataTask:task responseObject:nil error:error resultBlock:resultBlock];
             }];
             */
            
            [self.manager POST:url parameters:params success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
                //缓存数据
                if (resultBlock) {
                    NSData *data = [NSJSONSerialization dataWithJSONObject:responseObject options:NSJSONWritingPrettyPrinted error:nil];
                    [JD_CacheTool cacheForData:data fileName:fileName];
                    [self handleRequestReslutWithDataTask:task responseObject:responseObject error:nil resultBlock:resultBlock];
                }
            } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
                [self handleRequestReslutWithDataTask:task responseObject:nil error:error resultBlock:resultBlock];
            }];
        }
        case NetworkDeleteType:
        {
            [self.manager DELETE:url parameters:params success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
                //删除接口不需要做缓存
                if (resultBlock) {
                    [self handleRequestReslutWithDataTask:task responseObject:responseObject error:nil resultBlock:resultBlock];
                }
            } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
                [self handleRequestReslutWithDataTask:task responseObject:nil error:error resultBlock:resultBlock];
            }];
        }
        case NetworkPutType:
        {
            [self.manager PUT:url parameters:params success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
                [self handleRequestReslutWithDataTask:task responseObject:responseObject error:nil resultBlock:resultBlock];
            } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
                [self handleRequestReslutWithDataTask:task responseObject:nil error:error resultBlock:resultBlock];
            }];
        }
            
        default:
            break;
    }
}

- (void)handleRequestReslutWithDataTask:(NSURLSessionTask *)task responseObject:(id)responseObject error:(NSError *)error resultBlock:(JDBlock)resultBlock{
    //do something here...
//    NSLog(@"%@==-==%@",responseObject,error);
    if (resultBlock) {
        resultBlock(responseObject, error);
    }
}


/*
 -(void)requestWithURL:(NSString *)url withParams:(NSDictionary *)params withCacheType:(JDCacheType)cacheType withRequestType:(NetworkRequestType)requestType withResult:(JDBlock)resultBlock{
 if (!self.isConnected) {
 NSLog(@"没有网络");
 //        return;
 }
 switch (requestType) {
 case NetworkGetType:
 {
 JD_Cache *cache = [self getCache:cacheType url:url params:params withRequest:resultBlock];
 NSString *fileName = cache.fileName;
 if (cache.result) {
 return;
 }
 
 //            [self.manager GET:url parameters:params progress:^(NSProgress * _Nonnull downloadProgress) {
 //
 //            } success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
 //                NSLog(@"responseObject===%@", responseObject);
 //                if (resultBlock) {
 //                    //缓存数据
 //                    NSData *data = [NSJSONSerialization dataWithJSONObject:responseObject options:NSJSONWritingPrettyPrinted error:nil];
 //                    [JD_CacheTool cacheForData:data fileName:fileName];
 //                    [self handleRequestReslutWithDataTask:task responseObject:responseObject error:nil resultBlock:resultBlock];
 //                }
 //            } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
 //                NSLog(@"%@", error);
 //                [self handleRequestReslutWithDataTask:task responseObject:nil error:error resultBlock:resultBlock];
 //            }];
 
 [self.manager GET:url parameters:params success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
 if (resultBlock) {
 NSData *data = [NSJSONSerialization dataWithJSONObject:responseObject options:NSJSONWritingPrettyPrinted error:nil];
 [JD_CacheTool cacheForData:data fileName:fileName];
 [self handleRequestReslutWithDataTask:task responseObject:responseObject error:nil resultBlock:resultBlock];
 }
 } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
 [self handleRequestReslutWithDataTask:task responseObject:nil error:error resultBlock:resultBlock];
 }];
 }
 break;
 case NetworkPostType:
 {
 JD_Cache *cache = [self getCache:cacheType url:url params:params withRequest:resultBlock];
 NSString *fileName = cache.fileName;
 if (cache.result) {
 return;
 }
 
 //            [self.manager POST:url parameters:params progress:^(NSProgress * _Nonnull uploadProgress) {
 //
 //            } success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
 //                //缓存数据
 //                if (resultBlock) {
 //                    NSData *data = [NSJSONSerialization dataWithJSONObject:responseObject options:NSJSONWritingPrettyPrinted error:nil];
 //                    [JD_CacheTool cacheForData:data fileName:fileName];
 //                    [self handleRequestReslutWithDataTask:task responseObject:responseObject error:nil resultBlock:resultBlock];
 //                }
 //            } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
 //                [self handleRequestReslutWithDataTask:task responseObject:nil error:error resultBlock:resultBlock];
 //            }];
 
 
 [self.manager POST:url parameters:params success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
 //缓存数据
 if (resultBlock) {
 NSData *data = [NSJSONSerialization dataWithJSONObject:responseObject options:NSJSONWritingPrettyPrinted error:nil];
 [JD_CacheTool cacheForData:data fileName:fileName];
 [self handleRequestReslutWithDataTask:task responseObject:responseObject error:nil resultBlock:resultBlock];
 }
 } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
 [self handleRequestReslutWithDataTask:task responseObject:nil error:error resultBlock:resultBlock];
 }];
 }
 
 default:
 break;
 }
 }
 
 - (void)handleRequestReslutWithDataTask:(NSURLSessionTask *)task responseObject:(id)responseObject error:(NSError *)error resultBlock:(JDBlock)resultBlock{
 //do something here...
 NSLog(@"%@==-==%@",responseObject,error);
 if (resultBlock) {
 resultBlock(responseObject, error);
 }
 }
 */



@end




